<script setup lang="ts">
import type { Ref } from "vue";
import { ref, nextTick } from "vue";
import HumanChat from "./HumanChat.vue";
import AssistantChat from "./AssistantChat.vue";
import { ChatLoading } from "@/components/loading/index";
import { chatConversationApi } from "@/api";
import { Message } from "@arco-design/web-vue";
import { ChatType, History } from "@/api/types";

// 展开的输入文本框容器高度
const sendExpandedStyle = {
  height: "450px",
  boxShadow: "5px -8px 20px 0 rgba(0, 0, 0, .12)",
};
// 输入框高度大小
const textRow = {
  minRows: 2,
  maxRows: 2,
};
// 对话历史记录，传递给模型
let chatHistory: History[] = [];
const defaultChat: History = {
  role: "assistant",
  content: "您好！我是AI编程助手，有什么可以帮助您的吗？",
};

const isExpand = ref(false);
const loading = ref(false);
const humanInput = ref("");
// 响应式对话，界面显示
const chatting: Ref<History[]> = ref([defaultChat]);
const param: ChatType = {
  query: "AI编程助手",
  conversation_id: "",
  history_len: -1,
  history: [],
  stream: true,
  model_name: "openai-api",
  temperature: 0.7,
  max_tokens: 0,
  prompt_name: "default",
};

/**
 * 聊天输入框放大缩小
 */
function chatSendScaleClick() {
  isExpand.value = !isExpand.value;

  if (isExpand.value) {
    textRow.minRows = 16;
    textRow.maxRows = 16;
  } else {
    textRow.minRows = 2;
    textRow.maxRows = 2;
  }
}

/**
 * 滚动条，滚动到底部
 */
function scrollToBottom(div: Element | null) {
  if (div === null) {
    return;
  }
  nextTick(() => {
    const scroll = div;
    scroll.scrollTo({
      top: scroll.scrollHeight,
      behavior: "smooth",
    });
  });
}

/**
 * 输入框键盘事件
 * @param event KeyboardEvent
 */
function inputKeyboard(event: KeyboardEvent | Event) {
  let e = event as KeyboardEvent;
  if (e.key == "Enter" && e.ctrlKey) {
    // Ctrl + Enter 换行
    humanInput.value = humanInput.value + "\n";
    scrollToBottom(
      document
        .getElementsByClassName("chat-send-input")[0]
        .getElementsByClassName("el-textarea__inner")[0],
    );
  } else if (e.key == "Enter") {
    // Enter 提交
    event.preventDefault();
    onSubmit();
  }
}

/**
 * 输入框提交
 */
function onSubmit() {
  if (humanInput.value === "") {
    Message.warning("请输入对话内容");
    return;
  }

  let userChat: History = {
    role: "user",
    content: humanInput.value,
  };
  chatting.value.push(userChat);
  chatHistory.push(userChat);
  param.history = chatHistory.filter((chat: any) => !chat.error);
  // 调用对话接口
  chatConversationApi(param)
    .then((res: any) => {
      console.log(res);
      if (res.success) {
        let assistantChat = {
          role: "assistant",
          content: res.data.text,
        };
        param.conversation_id = res.data.message_id;
        chatting.value.push(assistantChat);
        chatHistory.push(assistantChat);
      }
    })
    .catch(() => {
      chatting.value.pop();
      chatHistory.pop();
      userChat.error = true;
      chatting.value.push(userChat);
    })
    .finally(() => {
      loading.value = false;
      scrollToBottom(document.getElementsByClassName("chat-card-body")[0]);
    });

  if (isExpand.value) {
    chatSendScaleClick();
  }
  humanInput.value = "";
  loading.value = true;

  scrollToBottom(document.getElementsByClassName("chat-card-body")[0]);
}

function onRestartNewChat() {
  clearHistory();
  chatting.value = [];
  Message.success("开始新对话");
  nextTick(() => {
    chatting.value.push(defaultChat);
  });
}

/**
 * 清除历史
 */
function clearHistory() {
  chatHistory = [];
  param.history = [];
  param.conversation_id = "";
  humanInput.value = "";
  isExpand.value = false;
  loading.value = false;
  textRow.minRows = 3;
  textRow.maxRows = 3;
}
</script>

<template>
  <div class="chat-card-body">
    <template v-for="(item, index) in chatting">
      <HumanChat
        :key="index"
        v-if="item.role === 'user'"
        :content="item.content"
        :error="item.error"
      ></HumanChat>
      <AssistantChat
        :key="index"
        v-if="item.role === 'assistant'"
        :content="item.content"
        :stream="index === chatting.length - 1"
      ></AssistantChat>
    </template>
    <div class="chat-loading" v-if="loading">
      <!--      <ChatLoading></ChatLoading>-->
      <a-spin dot :loading="loading" />
    </div>
  </div>

  <div class="chat-send-card" :style="isExpand ? sendExpandedStyle : undefined">
    <div class="chat-send-scale" @click="chatSendScaleClick">
      <icon-down v-if="isExpand" />
      <icon-up v-else />
    </div>
    <a-textarea
      :key="Number(isExpand)"
      class="chat-send-input"
      :max-length="2000"
      allow-clear
      show-word-limit
      :auto-size="textRow"
      v-model="humanInput"
      :focus="true"
      :readonly="loading"
      @keydown.enter="inputKeyboard"
      placeholder="请输入对话内容……换行请使用 Ctrl + Enter，发送可使用 Enter"
    />
    <div class="chat-send-bottom-controls">
      <a-button type="primary" text @click="onRestartNewChat">
        新对话
      </a-button>
      <div class="bottom-send">
        <a-button type="primary" text :disabled="loading" @click="onSubmit">
          <icon-send />
        </a-button>
      </div>
    </div>
  </div>
</template>

<style scoped>
.chat-card-body {
  width: 100%;
  height: 430px;
  overflow: auto;

  .chat-loading {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 20px;
  }
}

.chat-send-card {
  position: absolute;
  bottom: 0;
  left: 0;
  z-index: 10;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  width: 100%;
  max-width: 1200px;
  height: 150px;
  padding: 5px 10px;
  border: 1px solid var(--color-neutral-4);
  background-color: var(--color-bg-2);

  .chat-send-scale {
    height: 20px;
    text-align: center;

    icon-down,
    icon-up {
      width: 40px;
      cursor: pointer;
    }
  }

  .chat-send-input {
    flex: 1;
    :deep(.el-textarea__inner) {
      resize: none;
      border: 0;
      box-shadow: none;

      &:focus {
        outline: none;
        box-shadow: 0 0 0 1px var(--color-neutral-4) inset;
      }

      &:read-only {
        box-shadow: none;
      }
    }
  }

  .chat-send-bottom-controls {
    display: flex;
    align-items: center;
    justify-content: space-between;
    height: 35px;
    margin-top: 10px;

    .bottom-send {
      display: flex;
      align-items: center;

      a-button {
        margin-left: 10px;
      }
    }
  }
}
</style>
